package com.haofengsoft.scce.common.security;

import java.io.ByteArrayOutputStream;

/**
 * Created by Administrator on 2014/10/15.
 */
public class Base64Util {
    private Base64Util() {
    }

    private static final byte[] encodingTable = {
            (byte) 'A', (byte) 'B', (byte) 'C', (byte) 'D', (byte) 'E', (byte) 'F', (byte) 'G',
            (byte) 'H', (byte) 'I', (byte) 'J', (byte) 'K', (byte) 'L', (byte) 'M', (byte) 'N',
            (byte) 'O', (byte) 'P', (byte) 'Q', (byte) 'R', (byte) 'S', (byte) 'T', (byte) 'U',
            (byte) 'V', (byte) 'W', (byte) 'X', (byte) 'Y', (byte) 'Z',
            (byte) 'a', (byte) 'b', (byte) 'c', (byte) 'd', (byte) 'e', (byte) 'f', (byte) 'g',
            (byte) 'h', (byte) 'i', (byte) 'j', (byte) 'k', (byte) 'l', (byte) 'm', (byte) 'n',
            (byte) 'o', (byte) 'p', (byte) 'q', (byte) 'r', (byte) 's', (byte) 't', (byte) 'u',
            (byte) 'v', (byte) 'w', (byte) 'x', (byte) 'y', (byte) 'z',
            (byte) '0', (byte) '1', (byte) '2', (byte) '3', (byte) '4', (byte) '5', (byte) '6',
            (byte) '7', (byte) '8', (byte) '9',
            (byte) '+', (byte) '/'
    };

    private static final byte[] decodingTable;

    static {
        decodingTable = new byte[128];
        for (int i = 0; i < decodingTable.length; i++) decodingTable[i] = -1;
        for (int i = 'A'; i <= 'Z'; i++) {
            decodingTable[i] = (byte) (i - 'A');
        }
        for (int i = 'a'; i <= 'z'; i++) {
            decodingTable[i] = (byte) (i - 'a' + 26);
        }
        for (int i = '0'; i <= '9'; i++) {
            decodingTable[i] = (byte) (i - '0' + 52);
        }
        decodingTable['+'] = 62;
        decodingTable['/'] = 63;
    }

    public static byte[] encode(String data) {
        if (data == null || data.length() == 0) return new byte[0];
        return encode(data.getBytes());
    }

    public static byte[] encode(byte[] data) {
        if (data == null || data.length == 0) return new byte[0];
        ByteArrayOutputStream buf = new ByteArrayOutputStream((data.length / 3 + 1) * 4);
        int len = data.length;
        int i = 0;
        int b1, b2, b3;
        while (i < len) {
            b1 = data[i++] & 0xff;
            if (i == len) {
                buf.write(encodingTable[b1 >>> 2]);
                buf.write(encodingTable[(b1 & 0x3) << 4]);
                buf.write((byte) '=');
                buf.write((byte) '=');
                break;
            }
            b2 = data[i++] & 0xff;
            if (i == len) {
                buf.write(encodingTable[b1 >>> 2]);
                buf.write(encodingTable[((b1 & 0x03) << 4) | ((b2 & 0xf0) >>> 4)]);
                buf.write(encodingTable[(b2 & 0x0f) << 2]);
                buf.write((byte) '=');
                break;
            }
            b3 = data[i++] & 0xff;
            buf.write(encodingTable[b1 >>> 2]);
            buf.write(encodingTable[((b1 & 0x03) << 4) | ((b2 & 0xf0) >>> 4)]);
            buf.write(encodingTable[((b2 & 0x0f) << 2) | ((b3 & 0xc0) >>> 6)]);
            buf.write(encodingTable[b3 & 0x3f]);
        }
        return buf.toByteArray();
    }

    public static byte[] decode(String str) {
        if (str == null || str.length() == 0) return new byte[0];
        return decode(str.getBytes());
    }

    public static byte[] decode(byte[] data) {
        if (data == null || data.length == 0) return new byte[0];
        int len = data.length;
        ByteArrayOutputStream buf = new ByteArrayOutputStream(len);
        int i = 0;
        int b1, b2, b3, b4;
        while (i < len) {
            /* b1 */
            do {
                b1 = decodingTable[data[i++]];
            } while (i < len && b1 == -1);
            if (b1 == -1) break;
            /* b2 */
            do {
                b2 = decodingTable[data[i++]];
            } while (i < len && b2 == -1);
            if (b2 == -1) break;
            buf.write((int) ((b1 << 2) | ((b2 & 0x30) >>> 4)));
            /* b3 */
            do {
                b3 = data[i++];
                if (b3 == '=')
                    return buf.toByteArray();
                b3 = decodingTable[b3];
            } while (i < len && b3 == -1);
            if (b3 == -1) break;
            buf.write((int) (((b2 & 0x0f) << 4) | ((b3 & 0x3c) >>> 2)));
            /* b4 */
            do {
                b4 = data[i++];
                if (b4 == '=')
                    return buf.toByteArray();
                b4 = decodingTable[b4];
            } while (i < len && b4 == -1);
            if (b4 == -1) break;
            buf.write((int) (((b3 & 0x03) << 6) | b4));
        }
        return buf.toByteArray();
    }
}
